//
//  Base64Code.m
//  QCFM2
//
//  Created by iMac on 15/12/23.
//  Copyright © 2015年 kuai. All rights reserved.
//

#import <Foundation/Foundation.h>
#import <stdio.h>
#import <string.h>
#import <iostream>
#import <sys/types.h>
#import <ctime>
#import <exception>
#import <list>
#import <string>
#import <netinet/in.h>
#import <time.h>

using namespace std;

time_t nowTime;

/**
 * 单个gps点对象实体类
 */
class BaseProbeModel {
private:
    /** :degree */
    double x;
    /** degree */
    double y;
    /** :km/h */
    u_int8_t speed;
    /** 0-360 */
    int16_t direction;
    /**  声明为const的成员函数可以修改它的值 */
    mutable int altitude;
    /**  */
    time_t * date;
public:
    /**静态变量,每度相当于多少NTU*/
    static const int ONE_DEGREE_NTU=1e6;
    
    BaseProbeModel(){
        x=0;
        y=0;
        direction=90;
        speed=50;
        altitude=0;
        time_t temp =time_t(NULL);
        date=&temp;
    }
    BaseProbeModel(double xx,double yy,time_t &now, u_int8_t now_speed, int16_t direct) {
        x=xx;
        y=yy;
        altitude=0;
        date = &now;
        speed = now_speed;
        direction = direct;
    }
    
    virtual ~BaseProbeModel(){}
    /**
     * 只能读取数据，不能修改
     * @return
     */
    int getAltitude() const {
        return altitude;
    }
    
    void setAltitude(int altitude) {
        this->altitude = altitude;
    }
    
    time_t * getDate() const {
        printf("getgetgetgetget!!!\n");
        if (date == NULL) {
            return NULL;
        }
        //printf("%ld", *date);
        return date;
    }
    
    void setDate(time_t *date) {
        this->date = date;
    }
    
    int16_t getDirection() const {
        return direction;
    }
    
    void setDirection(int16_t direction) {
        this->direction = direction;
    }
    
    u_int8_t getSpeed() const {
        return speed;
    }
    
    void setSpeed(u_int8_t speed) {
        this->speed = speed;
    }
    
    double getX() const {
        return x;
    }
    
    void setX(double x) {
        this->x = x;
    }
    
    double getY() const {
        return y;
    }
    
    void setY(double y) {
        this->y = y;
    }
    
};
class ProbeModel {
private:
    /** 点列表 */
    list<BaseProbeModel> points;
    /** 终端标识id */
    string userId;
public:
    ProbeModel(){}
    virtual ~ProbeModel(){}
    
    void addBaseProbeModel(const BaseProbeModel& model){
        points.push_back(model);
    }
    
    void clearall(){
        points.clear();
    }
    
    const list<BaseProbeModel>& getPoints() const {
        return points;
    }
    
    const string& getUserId() const {
        return userId;
    }
    
    void setUserId(const string& userId) {
        this->userId = userId;
    }
    
};

static const char *g_pCodes =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";

static bool base64Encode(const unsigned char *pIn, unsigned long uInLen, string& strOut)
{
    unsigned long i, len2, leven;
    strOut = "";
    
    //ASSERT((pIn != NULL) && (uInLen != 0) && (pOut != NULL) && (uOutLen != NULL));
    
    len2 = ((uInLen + 2) / 3) << 2;
    //if((*uOutLen) < (len2 + 1)) return false;
    
    //p = pOut;
    leven = 3 * (uInLen / 3);
    for(i = 0; i < leven; i += 3)
    {
        strOut += g_pCodes[pIn[0] >> 2];
        strOut += g_pCodes[((pIn[0] & 3) << 4) + (pIn[1] >> 4)];
        strOut += g_pCodes[((pIn[1] & 0xf) << 2) + (pIn[2] >> 6)];
        strOut += g_pCodes[pIn[2] & 0x3f];
        pIn += 3;
    }
    
    if (i < uInLen)
    {
        unsigned char a = pIn[0];
        unsigned char b = ((i + 1) < uInLen) ? pIn[1] : 0;
        unsigned char c = 0;
        
        strOut += g_pCodes[a >> 2];
        strOut += g_pCodes[((a & 3) << 4) + (b >> 4)];
        strOut += ((i + 1) < uInLen) ? g_pCodes[((b & 0xf) << 2) + (c >> 6)] : '=';
        strOut += '=';
    }
    
    //*p = 0; // Append NULL byte
    //*uOutLen = p - pOut;
    return true;
}

/**判断字节序的大小端*/
static char checkOrderEndian()
{
    unsigned ui = ~0 - 1;
    return  ((*(unsigned char *)&ui==0xfe) ? 'L' : 'B');
}

/**
 *构建ugc格式数据
 * @param probe	 采集到的gps对象，包含多个位置点
 * @param endian 字节序类型,L-小端序,B-大端序
 * @return
 */
static string buildUgcLocationString(ProbeModel& probe,char endian) {
    //数据长度,不包括自身2字节
    short data_len = 0;
    //状态码
    int8_t navi_stat = 0;
    //位置点总数
    u_int8_t vertex_num = 0;
    int lon = 0;
    int lat = 0;
    int time = 0;
    u_int8_t speed = 0;
    //角度
    short angle = 0;
    //经纬度差值
    short lon_diff = 0;
    short lat_diff = 0;
    int8_t time_diff = -1;
    char _endR = '\r';
    char _endN = '\n';
    try {
        //设备标识
        u_char idArray [8];
        memcpy(idArray, probe.getUserId().c_str(), 8);
        list<BaseProbeModel> pointList = probe.getPoints();
        list<BaseProbeModel>::iterator it;
        it=pointList.begin();
        vertex_num = (u_int8_t) pointList.size();
        // (data_len - 2 - 25) / 8 = vertex_num - 1
        data_len = (short) ((vertex_num - 1) * 8 + 25 + 2);
        char* buffer = new char[(data_len + 2)];// =data_len=2
        memset(buffer, 0, data_len+2);
        //数组偏移值
        int offset(0);
        BaseProbeModel firstPoint = *pointList.begin();
        short tmp_data_len= endian=='B'?ntohs((unsigned short)data_len):data_len;
        memcpy(buffer+offset,&tmp_data_len,sizeof(data_len));
        offset+=sizeof(data_len);
        memcpy(buffer+offset,&idArray,sizeof(idArray));
        offset+=sizeof(idArray);
        memcpy(buffer+offset,&navi_stat,sizeof(navi_stat));
        offset+=sizeof(navi_stat);
        memcpy(buffer+offset,&vertex_num,sizeof(vertex_num));
        offset+=sizeof(vertex_num);
        lon = (int) (firstPoint.getX() * BaseProbeModel::ONE_DEGREE_NTU);
        lat = (int) (firstPoint.getY() * BaseProbeModel::ONE_DEGREE_NTU);
        //time获取方式改变一下
        time = (int) (*firstPoint.getDate());
        speed = firstPoint.getSpeed();
        angle = firstPoint.getDirection();
        lon = endian=='B'?ntohl((unsigned int)lon):lon;
        memcpy(buffer+offset,&lon,sizeof(lon));
        offset+=sizeof(lon);
        lat = endian=='B'?ntohl((unsigned int)lat):lat;
        memcpy(buffer+offset,&lat,sizeof(lat));
        offset+=sizeof(lat);
        time = endian=='B'?ntohl((unsigned int)time):time;
        memcpy(buffer+offset,&time,sizeof(time));
        offset+=sizeof(time);
        memcpy(buffer+offset,&speed,sizeof(speed));
        offset+=sizeof(speed);
        angle = endian=='B'?ntohs((unsigned short)angle):angle;
        memcpy(buffer+offset,&angle,sizeof(angle));
        offset+=sizeof(angle);
        for (it=++it;it!= pointList.end();++it) {
            // caculate
            BaseProbeModel currPoint = *it;
            int currLon = (int) (currPoint.getX() * currPoint.ONE_DEGREE_NTU);
            int currLat = (int) (currPoint.getY() * BaseProbeModel::ONE_DEGREE_NTU);
            int currTime = ( int) (*currPoint.getDate());
            lon_diff = (short) (currLon - lon);
            lat_diff = (short) (currLat - lat);
            time_diff = (int8_t) (currTime - time);
            speed = currPoint.getSpeed();
            angle = currPoint.getDirection();
            lon_diff = endian=='B'?ntohs((unsigned short)lon_diff):lon_diff;
            memcpy(buffer+offset,&lon_diff,sizeof(lon_diff));
            offset+=sizeof(lon_diff);
            lat_diff=endian=='B'?ntohs((unsigned short)lat_diff):lat_diff;
            memcpy(buffer+offset,&lat_diff,sizeof(lat_diff));
            offset+=sizeof(lat_diff);
            memcpy(buffer+offset,&time_diff,sizeof(time_diff));
            offset+=sizeof(time_diff);
            memcpy(buffer+offset,&speed,sizeof(speed));
            offset+=sizeof(speed);
            angle=endian=='B'?ntohs((unsigned short)angle):angle;
            memcpy(buffer+offset,&angle,sizeof(angle));
            offset+=sizeof(angle);
            lon = currLon;
            lat = currLat;
            time = currTime;
        }
        memcpy(buffer+offset,&_endR,sizeof(_endR));
        offset+=sizeof(_endR);
        memcpy(buffer+offset,&_endN,sizeof(_endN));
        offset+=sizeof(_endN);
        string base64str;
        bool ret = base64Encode((const unsigned char*)buffer,data_len + 2,base64str);
        return base64str;//
    } catch (exception &e) {
        //	CLogHelper::log(LOG_ERROR,strcat((char*)"probe,msg=",e.what()));
    }
    return "NULL";
}

ProbeModel probeModel = ProbeModel();
ProbeModel &probe = probeModel;

@implementation TestSwift2OC : NSObject

-(void)SetTime
{
    nowTime = time(NULL);
}

-(void)SetProbe: (string) license
{
    probe.setUserId(license);
}

-(void)clearAll
{
    probe.clearall();
}

-(void)AddXY: (double) longitude para2:(double) latitude para3:(double) speed para4:(double) direct para5: (int) num para6:(int)time
{
    time_t test = (time_t)time;
    time_t *now = &test;
    
    printf("printf all zuobiao time\n");
    printf("time:%ld\n", *now);
    
    BaseProbeModel model(longitude, latitude, *now, int(speed), int(direct));
    
    probe.addBaseProbeModel(model);
}

-(NSString *)EncodeBase64
{
    char endian = checkOrderEndian();
    //用指针函数调用
    string (*pUgc)(ProbeModel&,char) = &buildUgcLocationString;
    string ugcStr = (*pUgc)(probe,endian);
    std::string test1(ugcStr);
    NSString *str= [NSString stringWithCString:test1.c_str() encoding:[NSString defaultCStringEncoding]];
    return str;
}


@end

